﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using EnetaMvc.Infrastructure;
using NHibernate;

namespace EnetaMvc.Data.NHibernate.Repositories
{
    public abstract class BaseRepository
    {
        private readonly ISession _session;

        public BaseRepository(ISession session)
        {
            _session = session;
        }

        protected PagedResult<T> GetPagedResultForQuery<T>(ICriteria criteria, int page, int pageSize)
        {
            var countCriteria = CriteriaTransformer.TransformToRowCount(criteria);
            criteria.SetMaxResults(pageSize).SetFirstResult((page - 1) * pageSize);
            var multi = _session.CreateMultiCriteria().Add(countCriteria).Add(criteria).List();
            var result = new PagedResult<T>();
            result.CurrentPage = page;
            result.PageSize = pageSize;
            result.RowCount = (int)((IList)multi[0])[0];

            var pageCount = (double)result.RowCount / result.PageSize;
            result.PageCount = (int)Math.Ceiling(pageCount);
            result.Results = ((IList)multi[1]).Cast<T>().ToList();
            return result;
        }

        protected void SaveInTransaction(object o)
        {
            using (var tran = _session.BeginTransaction())
            {
                try
                {
                    _session.SaveOrUpdate(o);
                    tran.Commit();
                }
                catch
                {
                    tran.Rollback();
                    throw;
                }
            }
        }

        protected void DeleteInTransaction(object instance)
        {
            using (var tran = _session.BeginTransaction())
            {
                try
                {
                    _session.Delete(instance);
                    tran.Commit();
                }
                catch
                {
                    tran.Rollback();
                    throw;
                }
            }
        }

        internal void Validate(object instance)
        {
            var context = new ValidationContext(instance, null, null);
            var validationErrors = new List<ValidationResult>();


            if (!Validator.TryValidateObject(instance, context, validationErrors, true))
                throw new MultiValidationException(validationErrors);
        }
    }
}
